package com.learn.temp.api;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author wangxing
 * @version 2020/6/11 6:53 Administrator
 */
public class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] b = loadClassByte(name);
            return defineClass(name, b, 0, b.length);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        }
    }

    private static Object lock;

    private Object getLock() {
        if (lock == null) {
            lock = new Object();
        }
        return lock;
    }

    /**
     * 打破双亲委派机制的类加载器方法
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    public Class<?> loadClassBreak(String name) throws ClassNotFoundException {
        Class c = null;
        synchronized (getLock()) {
            long t0 = System.nanoTime();
            if (name.startsWith("java.lang")) {
                return super.loadClass(name);
            } else {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
            if (resolve) {
                resolveClass(c);
            }
        }
        return c;
    }

    private String classPath;
    private boolean resolve = false;

    public void setResolve(boolean resolve) {
        this.resolve = resolve;
    }

    public String getClassPath() {
        return classPath;
    }

    public MyClassLoader(String classPath) {
        this.classPath = classPath;
    }

    private byte[] loadClassByte(String name) throws IOException {
        byte[] data;
        name = name.replaceAll("\\.", "/");
        FileInputStream inputStream = new FileInputStream(getClassPath() + "/" + name + ".class");
        int size = inputStream.available();
        data = new byte[size];
        inputStream.read(data);
        inputStream.close();
        return data;
    }
}
